//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Windows.Documents;
using OpenLS.Spreadsheet.Expressions;
using OpenLS.Spreadsheet.Extensibility;

namespace OpenLS.Spreadsheet
{
    sealed class FullWorksheetRange: SimpleRange
    {
        internal override bool IsProtected
        {
            get { return Worksheet.Protection != null; }
        }
        internal override IEnumerable<CellFormattingRecord> GetFormattingRecords()
        {
            foreach (var row in this.GetNonEmptyRows())
                yield return row.FormattingRecord;
            foreach (var column in this.GetNonEmptyColumns())
                yield return column.FormattingRecord;
            foreach (var cell in this.GetNonEmptyCells())
                yield return cell.FormattingRecord;
        }
        public FullWorksheetRange(Worksheet worksheet)
        {
            _worksheet = worksheet;
        }
        internal override IEnumerable<SimpleRange> GetSimpleRanges()
        {
            yield return this;
        }

        readonly Worksheet _worksheet;
        public override Cell TopLeftCell
        {
            get { return Worksheet[0, 0]; }
        }
        internal override bool Contains(Range range)
        {
            return true;
        }

        internal override void CopyFromImp(CellAddress sourceTopLeft, IEnumerable<SimpleRange> sources, PasteInfo pasteInfo)
        {
            var fn = pasteInfo.Functions;
            if (fn.ClearDimension != null)
            {
                foreach (Row dim in Worksheet.Rows)
                    fn.ClearDimension(dim);
                foreach (Column dim in Worksheet.Columns)
                    fn.ClearDimension(dim);
            }
            foreach (Cell cell in GetNonEmptyCells())
                fn.ClearCell(cell);
            foreach (var source in sources)
            {
                foreach (Row row in source.GetNonEmptyRows())
                {
                    fn.CopyRowcolumnFunction(row, Worksheet.Rows[row.Index]);
                }
                foreach (Column column in source.GetNonEmptyColumns())
                {
                    fn.CopyRowcolumnFunction(column, Worksheet.Columns[column.Index]);
                }
                foreach (Cell cell in source.GetNonEmptyCells())
                    fn.CopyFunction(cell, Worksheet[cell.Address], pasteInfo);
            }
        }

        internal override bool IsSingleCell
        {
            get { return false; }
        }

        internal override Range GetColumnRange(int index, RangeType type)
        {
            return new FullColumnRange(Worksheet.Columns[index]);
        }

        internal override Range GetRowRange(int index, RangeType type)
        {
            return new FullRowRange(Worksheet.Rows[index]);
        }

        public override Cell this[int row, int column]
        {
            get{
            return Worksheet[row, column];
            }
        }

        internal override RangeAddress Address
        {
            get
            {
                return new RangeAddress(new CellAddress(0, 0), new CellAddress(Worksheet.MaxRowIndex, Worksheet.MaxColumnIndex));
            }
        }

        internal override Cell FirstCell
        {
            get { return TopLeftCell; }
        }

        public override int RowSpan
        {
            get { return Worksheet.MaxRowIndex + 1; }
        }

        public override int ColumnSpan
        {
            get { return Worksheet.MaxColumnIndex + 1; }
        }

        public override bool IsFullRow
        {
            get { return true; }
        }

        public override bool IsFullColumn
        {
            get { return true; }
        }

        internal override void SetCellValueNoUndo(CellProperty p, object value)
        {
            foreach (Cell cell in Worksheet.GetCells())
            {
                cell.SetCellValue(p, value);
            }
            foreach (Column column in Worksheet.Columns)
                column.SetCellValue(p, value);
            foreach (Row row in Worksheet.Rows)
                row.SetCellValue(p, value);
        }

        public override Worksheet Worksheet
        {
            get { return _worksheet; }
        }

        public override string Label
        {
            get { return "1:1048576"; }
        }

        internal override object GetFirstCellValue(CellProperty p)
        {
            throw new NotImplementedException();
        }

        internal override CellFormattingRecord GetFormattingRecord()
        {
            throw new NotImplementedException();
        }

        internal override object GetCellValue(CellProperty p, out bool uniform)
        {
            uniform = false;
            return null;
        }

        internal override void SetBorderNoUndo(Border border, BorderType borderType)
        {
            FullColumnRange r = new FullColumnRange(this.Worksheet.Columns[0], this.Worksheet.Columns[Spreadsheet.Worksheet.MaxColumnIndex]);
            r.SetBorderNoUndo(border, borderType);
        }

        internal override void SetColumnsWidthNoUndo(double value)
        {
            Worksheet.DefaultColumnWidth = value;
            var columns = new List<Column>(Worksheet.Columns);
            foreach (Column column in columns)
            {
                column.Width = null;
            }
            Worksheet.Columns.RaiseLayoutChanged(null);

        }
        internal override void SetRowsHeightNoUndo(double value)
        {
            Worksheet.DefaultRowHeight = value;
            var rows = new List<Row>(Worksheet.Rows);
            foreach (Row row in rows)
            {
                row.Height = null;
                
                Contract.Assert(row.ActualHeight == value);
            }
            Worksheet.Rows.RaiseLayoutChanged(null);
        }

        internal override Border GetBorder(BorderType borderType, out bool uniform)
        {
            throw new NotImplementedException();
        }

        internal override IEnumerable<Cell> GetNonEmptyCells()
        {
            return Worksheet.GetCells();
        }

        internal override IEnumerable<PartialRowOrColumnRange> GetPartialRowOrColumnRanges(RowOrColumn c)
        {
            throw new NotImplementedException();
        }

        internal override bool Contains(CellAddress address)
        {
            return true;
        }

        internal override void SetStyleNoUndo(CellStyle s)
        {
            new FullColumnRange(this.Worksheet.Columns[0], this.Worksheet.Columns[Worksheet.MaxColumnIndex]).SetStyleNoUndo(s);
            //\\throw new NotImplementedException();
        }

        internal override Cell GetNextCell(Cell cell, CellNavigationDirection direction)
        {
            switch (direction)
            {
                case CellNavigationDirection.Forward:

                    if (cell.Column.Index + cell.ColumnSpan <= Worksheet.MaxColumnIndex)
                        return Worksheet[cell.Row.Index, cell.Column.Index + +cell.ColumnSpan];
                    if (cell.Row.Index + cell.RowSpan <= Worksheet.MaxRowIndex)
                        return Worksheet[cell.Row.Index + cell.RowSpan, cell.Column.Index];
                    return Worksheet[0, 0];
                case CellNavigationDirection.Backward:
                    if (cell.Column.Index > 0)
                        return Worksheet[cell.Row.Index, cell.Column.Index + -1];
                    if (cell.Row.Index + cell.RowSpan > 0)
                        return Worksheet[cell.Row.Index - 1, cell.Column.Index];
                    return Worksheet[Worksheet.MaxRowIndex, Worksheet.MaxColumnIndex];
                default: throw new NotSupportedException();
            }
        }

        internal override RangeReference ToReference()
        {
            throw new NotImplementedException();
        }

        internal override FlowDocument ToFlowDocument(string columnSeparator)
        {
            MultiCellsRange r = toMultiCellsRange();
            return r.ToFlowDocument(columnSeparator);
        }
        private MultiCellsRange toMultiCellsRange()
        {
            int minRow = FirstCell.Row.Index;
            int maxRow = minRow;
            int minColumn = FirstCell.Column.Index;
            int maxColumn = minColumn;
            foreach (Cell c in GetNonEmptyCells())
            {
                minRow = Math.Min(minRow, c.Row.Index);
                maxRow = Math.Max(maxRow, c.Row.Index);
                minColumn = Math.Min(minColumn, c.Column.Index);
                maxColumn = Math.Max(maxColumn, c.Column.Index);
            }
            return new MultiCellsRange(Worksheet[minRow, minColumn], Worksheet[maxRow, maxColumn]);
        }

        public override IEnumerable<Cell> GetAllCells()
        {
throw new NotSupportedException();        }

        internal override Range Offseted(CellRelativeAddress address)
        {
            return this;
        }

        public override IEnumerable<Column> GetColumns()
        {
            return Worksheet.Columns;
        }
        internal override IEnumerable<Column> GetNonEmptyColumns()
        {
            return Worksheet.Columns;
        }

        public override IEnumerable<Row> GetRows()
        {
            throw new NotSupportedException();
        }
        internal override IEnumerable<Row> GetNonEmptyRows()
        {
            return Worksheet.Rows;
        }

        internal override SimpleRange ProjectedSimple(Worksheet worksheet, CellRelativeAddress diff)
        {
            if (worksheet == this.Worksheet)
                return this;
            return new FullWorksheetRange(worksheet);
        }
    }
}
